package middlewares

import (
	"strings"
	"supershare/backend/utils"

	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/golang-jwt/jwt/v5"
)

// JWTMiddleware 验证JWT的中间件
func JWTMiddleware() func(ctx *context.Context) {
	return func(ctx *context.Context) {
		// 从请求头获取token
		authHeader := ctx.Input.Header("Authorization")
		if authHeader == "" {
			// 如果请求头中没有Authorization，从查询参数中获取
			token := ctx.Input.Query("token")
			if token != "" {
				authHeader = "Bearer " + token
			}
		}

		// 检查token
		if authHeader == "" {
			// 无token
			ctx.ResponseWriter.WriteHeader(401)
			ctx.Output.JSON(utils.ResponseFail("未授权的访问，请先登录"), false, false)
			return
		}

		// Bearer Token格式
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			ctx.ResponseWriter.WriteHeader(401)
			ctx.Output.JSON(utils.ResponseFail("无效的Token格式"), false, false)
			return
		}

		// 解析token
		secretKey, err := web.AppConfig.String("jwtkey")
		if err != nil {
			ctx.ResponseWriter.WriteHeader(500)
			ctx.Output.JSON(utils.ResponseFail("系统错误，无法获取JWT key"), false, false)
			return
		}

		token, err := jwt.Parse(parts[1], func(token *jwt.Token) (interface{}, error) {
			// 验证签名算法
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, jwt.ErrSignatureInvalid
			}
			return []byte(secretKey), nil
		})

		if err != nil {
			ctx.ResponseWriter.WriteHeader(401)
			if err == jwt.ErrSignatureInvalid {
				ctx.Output.JSON(utils.ResponseFail("无效的Token签名"), false, false)
			} else {
				ctx.Output.JSON(utils.ResponseFail("无效的Token: "+err.Error()), false, false)
			}
			return
		}

		// 验证token是否有效
		if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
			// 将用户ID存入上下文
			userId, ok := claims["user_id"].(float64)
			if !ok {
				ctx.ResponseWriter.WriteHeader(401)
				ctx.Output.JSON(utils.ResponseFail("无效的Token payload"), false, false)
				return
			}

			// 将用户ID和OpenID存入上下文
			ctx.Input.SetData("user_id", int64(userId))

			if openid, ok := claims["openid"].(string); ok {
				ctx.Input.SetData("openid", openid)
			}

			// 继续处理请求
		} else {
			ctx.ResponseWriter.WriteHeader(401)
			ctx.Output.JSON(utils.ResponseFail("无效的Token"), false, false)
			return
		}
	}
}
